using System;
using System.Windows.Forms;

namespace nToolbox.WinForms
{
	/// <summary>
	/// Delays drawing of a control to prevent flicker that would otherwise occur.
	/// </summary>
	/// <remarks>
	/// This class is meant to be used inside a using block:
	/// <code>
	/// using(new DelayPainting(someControl))
	/// {
	///		// Do work here that would otherwise create a lot of redraw and flicker.
	/// }
	/// </code>
	/// </remarks>
	public class DelayPainting : IDisposable
	{
		private readonly Control control;
		private int paintFrozen;

		private void Freeze()
		{
			if (control.IsHandleCreated && control.Visible)
			{
				if (0 == paintFrozen)
					User32.SendMessage(control.Handle, User32.WM_SETREDRAW, 0, 0);

				paintFrozen++;
			}
		}

		private void Unfreeze()
		{
			if (paintFrozen == 0)
				return;

			paintFrozen--;
			if (0 == paintFrozen)
			{
				User32.SendMessage(control.Handle, User32.WM_SETREDRAW, 1, 0);
				control.Invalidate(true);
			}
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="aControl">The control to temporarily suspend painting on.</param>
		public DelayPainting(Control aControl)
		{
			control = aControl;
			Freeze();
		}

		private bool disposed;

		private void Dispose(bool disposing)
		{
			if (!disposed && disposing)
				while (paintFrozen > 0) Unfreeze();

			disposed = true;
		}

		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		~DelayPainting()
		{
			Dispose(false);
		}
	}
}